package com.example.order.exception;

import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.commons.R;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;

import java.io.PrintWriter;

/**
 * Web接口：SentinelWebInterceptor
 * Controller兜底回调
 * 自定义 Sentinel 全局限流异常处理器类，实现了 BlockExceptionHandler 接口。在 Sentinel 的 Web 应用中，当你使用了 Sentinel Web Filter（即对 URL 级别进行保护）时，这个类的作用是：
 * 当 Sentinel 规则触发（如限流、熔断）时，不直接抛出异常，而是优雅地给客户端返回一个结构化的 JSON 响应
 * Sentinel 默认使用的是 DefaultBlockExceptionHandler，你自己实现这个接口并注册为 Bean 后，会自动替代默认实现。
 */
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
    /**
     * Jackson 提供的 ObjectMapper：用于将 Java 对象序列化成 JSON 字符串。
     */
    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * handle 方法是 BlockExceptionHandler 接口中唯一需要实现的方法。
     * 它在 Sentinel 拦截请求（如 QPS 超限）并抛出 BlockException 后触发。
     * | 参数                             | 含义
     * | `HttpServletRequest request`    | 原始请求对象
     * | `HttpServletResponse response`  | 原始响应对象
     * | `String resourceName`           | 被限流的资源名称（通常是 URL、方法名等）
     * | `BlockException e`              | 被触发的 Sentinel 异常，可能是 FlowException、DegradeException 等
     */
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, String resourceName, BlockException e) throws Exception {
        /**
         * 设置响应状态码
         */
        response.setStatus(429);
        /**
         * 设置响应头类型为 JSON。
         * 确保浏览器或前端看到的是 JSON，而不是 HTML 错误页。
         */
        response.setContentType("application/json;charset=utf-8");
        /**
         * 获取响应输出流，用于输出你自定义的 JSON 内容。
         */
        PrintWriter writer = response.getWriter();
        R error = R.error(500, resourceName + "被 Sentinel 限制了，原因为：" + e.getClass() + "Controller兜底回调");
        /**
         * 使用 Jackson 将 R 对象序列化成 JSON 字符串
         */
        String json = objectMapper.writeValueAsString(error);
        /**
         * 向客户端输出内容
         * 刷新缓冲区并关闭资源，确保响应顺利发送
         */
        writer.write(json);
        writer.flush();
        writer.close();
    }
}
/**
 * | 路径      | 拦截点                  | 适用场景              | 是否支持 blockHandler | 是否支持 fallback | 是否支持全局处理 |
 * | Web 接口  | SentinelWebInterceptor  | Controller 级接口保护 | ✅ 自定义 handler    | ❌              | ✅                |
 * | 注解方式  | SentinelResourceAspect  | 细粒度方法限流、熔断    | ✅                  | ✅              | ✅                |
 * | Feign方式 | SentinelFeign.builder() | 微服务间调用保护      | ❌（用fallback类）    | ✅              | ✅                |
 * | 编程方式  | SphU.tryEntry()         | 核心代码块            | ❌（需手动）          | ❌（需手动）      | ✅                |
 */